﻿using System;
using System.Configuration;
using System.Linq;
using System.Reflection;
using FluentIoC.Configuration;

namespace FluentIoC
{
    public static class IoC
    {
        private static ContainerManager _containerManager = new ContainerManager();

        public static IContainer Container
        {
            get { return _containerManager.Container; }
        }

        #region Configuration

        public static void ConfigureFromAssembly()
        {
            ConfigureFromAssembly(Assembly.GetCallingAssembly());
        }

        public static void ConfigureFromAssembly(string assembly)
        {
            ConfigureFromAssembly(Assembly.Load(assembly));
        }

        public static void ConfigureFromAssembly(Assembly assembly)
        {
            var configurations = assembly.GetTypes()
                .Where(t => t.IsSubclassOf(typeof(ContainerConfiguration)));

            if (configurations.Count() > 0)
            {
                foreach(var config in configurations)
                {
                    _containerManager.AddConfiguration(Activator.CreateInstance(config) as ContainerConfiguration);
                }
            }

            throw new ConfigurationErrorsException("No configuration types could be loaded from " + assembly.GetName().Name);
        }

        public static void Configure(params Action<ContainerConfiguration>[] actions)
        {
            var config = new ContainerConfiguration();

            foreach (var action in actions)
            {
                action(config);
            }

            _containerManager.AddConfiguration(config);
        }  

        public static void Configure(params Type[] configurations)
        {
            _containerManager.AddContainers(configurations);
        }

        public static void Reset()
        {
            _containerManager = new ContainerManager();
        }

        #endregion
        
        public static T Resolve<T>()
        {
            return Container.Resolve<T>();
        }

        public static T Resolve<T>(string name)
        {
            return Container.Resolve<T>(name);
        }

        public static T Resolve<T>(object param)
        {
            return Container.Resolve<T>(param);
        }

        public static T[] ResolveAll<T>()
        {
            return Container.ResolveAll<T>();
        }

        public static Array ResolveAll(Type type)
        {
            return Container.ResolveAll(type);
        }

        public static object Resolve(Type type)
        {
            return Container.Resolve(type);
        }
    }
}
